/*
 * @FilePath: \Src\Middlieware\iolib\io_lib.h
 * @Description: 
 * 食用方式：
 * 例：led
 * 第一步：在led.c中构造两个结构体；需要提供初始化、打开、关闭这三个函数
    static io_operation_t drv_led = {
        .init = led_init,
        .io_disable = led_set,
        .io_enable = led_reset,
    };

    io_device_t led = {
        .type = (const int8_t*)"led",
        .drv = &drv_led,
    };
 * 第二步：通过 io_device_register() 函数将led设备注册到设备列表
           设备列表的大小通过 DEVICE_MAX 调整
 * 第三步：
 * 一、有定时器提供时基
 *     1、将 IO_TICKS_PERIOD 宏配置为定时器的周期时间
 *        例:#define IO_TICKS_PERIOD 1
 *     2、在定时器中断中调用 io_tick_inc() 函数
 *     3、在主循环中调用 io_device_task() 函数
 *     4、通过 io_set_param() 函数设置io输出的参数
 *        例:io_set_param((const int8_t*)"led", IO_OUTPUT_MS_TO_TICKs(200),
 *           IO_OUTPUT_MS_TO_TICKs(200), IO_OUTPUT_LOOP, IO_OUTPUT_MS_TO_TICKs(0));
 * 二、无定时器提供时基时，不推荐使用该程序；如果硬要使用，则不需要调用 io_tick_inc()、
 * io_device_task()以及io_set_param()函数；而是注册后通过 void io_set_level(const io8_t *name, uio8_t new_level)
 * 函数直接设置电平。
 * Copyright (c) 2025 by ${w}, All Rights Reserved. 
 */

#ifndef IO_LIB_H
#define IO_LIB_H

#include "debug.h"

/*****************************数据类型*****************************/
typedef unsigned char uio8_t;
typedef signed char io8_t;
typedef unsigned short uio16_t;
typedef signed short io16_t;
typedef unsigned int uio32_t;
typedef signed int io32_t;

/* 为io设备提供的系统周期 单位ms */
#define IO_TICKS_PERIOD 1
/* 将ms数转换为tick数 */
#define IO_OUTPUT_MS_TO_TICKs(ms) ((uio16_t)(ms / IO_TICKS_PERIOD))

/* 空指针宏定义 */
#define io_ptr ((void *)0)
/* 可注册的最大设备数量 */
#define DEVICE_MAX 2
/* 返回值宏定义 */
#define IO_TRUE 1
#define IO_FALSE 0
/* IO输出类型 停止 */
#define IO_OUTPUT_STOP 0x0000
/* IO输出类型 死循环 */
#define IO_OUTPUT_LOOP 0xFFFF
/* IO输出类型 循环x次 */
#define IO_OUTPUT_COUNT(x) ((uio16_t)(x))

/* 输出任务状态 */
typedef enum
{
    IO_IDEL = 0,
    IO_WAIT_START,
    IO_ENABLE,
    IO_DISABLE,
    IO_DONE
} io_State;

/* io操作接口以及相关变量 */
typedef struct 
{
    /* 初始化函数指针  */
    void (*init)(void);
    /* 使能输出函数指针 */
    void (*io_enable)(void);
    /* 失能输出函数指针 */
    void (*io_disable)(void);
    /* io输出是否开启 */
    uio8_t io_open;
    /* io输出延迟时间 */
    uio16_t wait_time;
    /* io使能输出时间 */
    uio16_t enable_time;
    /* io失能输出时间 */
    uio16_t disable_time;
    /* io输出循环周期（次数） */
    uio16_t loop_count;
    /* io输出当前已进行的周期（次数） */
    uio16_t current_count;
    /* 下次时间 */
    uio32_t last_tick;
    /* 当前状态 */
    io_State state;
}io_operation_t;

/* 设备接口 */
typedef struct
{
    /* 设备名称 */
    const io8_t *type;
    /* 对应设备的操作接口 */
    io_operation_t *drv;
}io_device_t;

/*=============================内部调用函数==================================*/
/* 简单的字符串比较函数 */
static uio8_t io_compare_str(const io8_t *s1, const io8_t *s2);
/* 设备初始化 */
static void io_device_init(io_device_t *dev);
/* 设备使能 */
static void io_device_enable(io_device_t *dev);
/* 设备失能 */
static void io_device_disable(io_device_t *dev);
/* 根据设备名称查找对应的设备 */
static io_operation_t* io_device_found(const io8_t *name);
/* 设备轮询状态机 */
static void io_run_function(io_device_t *dev);
/* 获取当前时间戳 */
static uio32_t io_tick_get(void);

/*=============================外部调用函数==================================*/
/* 设备注册函数 */
void io_device_register(io_device_t *dev);
/* 在主程序中调用此函数 */
void io_device_task(void);
/* 设置io输出的状态 控制的设备名称 使能时间 失能时间 要循环的次数 延迟启动时间 */
void io_set_param(const io8_t *name, uio16_t enable_ms, uio16_t disable_ms, uio16_t loop_count, uio16_t wait_ms);
/* 设置某一设备的电平 */
void io_set_level(const io8_t *name, uio8_t new_level);
/* 为系统提供时基需要再定时器中断中调用 注意要把IO_TICKS_PERIOD配置为实际的定时器周期时间 */
void io_tick_inc(void);

#endif // !IO_LIB_H